#include "Vector3d.h"

Vector3d::Vector3d() {
    //Nothing.
}

Vector3d::Vector3d(double x, double y, double z) {
    this->x = x;
    this->y = y;
    this->z = z;
}


Vector3d Vector3d::randomCube(double min, double max) {
    return Vector3d(randdouble(min, max), randdouble(min, max), randdouble(min, max));
}

double Vector3d::magnitude() const {
    return sqrt(x*x + y*y + z*z);
}

double Vector3d::magnitude2d() const {
    return sqrt(x*x + y*y);
}

double Vector3d::normalize() {
    double r = magnitude();
    if (r > 0) {
        x /= r;
        y /= r;
        z /= r;
    }
    return r;
}

Vector3d Vector3d::getNormalized() const {
    Vector3d result(x, y, z);
    result.normalize();
    return result;
}

double Vector3d::normalize2d() {
    double s = magnitude2d();
    x /= s;
    y /= s;
    z /= s;
    return s;
}

double Vector3d::getSlope() {
    double s = magnitude2d();
    return z / s;
}

void Vector3d::rotateLeft(double angle) {
    double lastX = x;
    double lastZ = z;
    double cosAngle = cos(angle);
    double sinAngle = sin(angle);

    z = lastZ * cosAngle - lastX * sinAngle;
    x = lastX * cosAngle + lastZ * sinAngle;
}

void Vector3d::rotateUp(double angle) {
    double lastS = sqrt(x*x + z*z);
    double cosAngle = cos(angle);
    double sinAngle = sin(angle);

    double s = lastS * cosAngle - y * sinAngle;
    x = s * x / lastS;
    z = s * z / lastS;
    y = y * cosAngle + lastS * sinAngle;
}

Vector3d Vector3d::operator-() const {
    return Vector3d(-x, -y, -z);
}

Vector3d Vector3d::operator+(const Vector3d& v) const {
    return Vector3d(x + v.x, y + v.y, z + v.z);
}

void Vector3d::operator+=(const Vector3d& v) {
    x += v.x;
    y += v.y;
    z += v.z;
}

Vector3d Vector3d::operator-(const Vector3d& v) const {
    return Vector3d(x - v.x, y - v.y, z - v.z);
}

void Vector3d::operator-=(const Vector3d& v) {
    x -= v.x;
    y -= v.y;
    z -= v.z;
}

double Vector3d::operator*(const Vector3d& v) const {
    return x*v.x + y*v.y + z*v.z;
}

Vector3d Vector3d::operator^(const Vector3d& v) const {
    return Vector3d(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
}

Vector3d operator*(const Vector3d& v, double f) {
    return Vector3d(f * v.x, f * v.y, f * v.z);
}

Vector3d operator*(double f, const Vector3d& v) {
    return Vector3d(f * v.x, f * v.y, f * v.z);
}

Vector3d operator/(const Vector3d& v, double f) {
    return Vector3d(v.x / f, v.y / f, v.z / f);
}

void Vector3d::operator/=(double f) {
    x /= f;
    y /= f;
    z /= f;
}

ostream& operator<<(ostream& os, Vector3d& v) {
    os << v.x << " " << v.y << " " << v.z;
    return os;
}

istream& operator>>(istream& is, Vector3d& v) {
    is >> v.x >> v.y >> v.z;
    return is;
}

bool Vector3d::timeInRect(double& minT, double& maxT, double dirX, double dirY, double minX, double maxX, double minY, double maxY) const {
    double minTx = (minX - x) / dirX;
    double maxTx = (maxX - x) / dirX;
    if (minTx > maxTx) swap(minTx, maxTx);
    if (maxTx < 0.0) return false;

    double minTy = (minY - y) / dirY;
    double maxTy = (maxY - y) / dirY;
    if (minTy > maxTy) swap(minTy, maxTy);
    if (maxTy < 0.0) return false;

    minT = max(minTx, minTy);
    maxT = min(maxTx, maxTy);
    if (minT < 0.0) minT = 0.0;
    if (minT > maxT) return false;

    return true;
}

void Vector3d::glVertex() const {
    glVertex3d(x, y, z);
}

void Vector3d::glNormal() const {
    glNormal3d(x, y, z);
}